﻿#define FORCE_LOCAL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure;
using System.Diagnostics;
using System.IO;
using System.Web;
using System.Reflection;
using System.Configuration;


namespace LoadStorage
{
    class Program
    {
        static void Main(string[] args)
        {

            //this setting contains the path to the files to move to Azure Storage
            string ProjectResourcesDirRoot = ConfigurationManager.AppSettings["ResourcesRoot"];

            //the value in this setting should match the value in the AzureStorageCacheContainer setting for the web role
            string BlobContainerName = ConfigurationManager.AppSettings["TargetContainer"];
            //string SourcePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);

            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                // for a console app, reading from App.config
                configSetter(ConfigurationManager.AppSettings[configName]);
                // OR, if running in the Windows Azure environment
                // configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
            });

            CloudStorageAccount StorageAccount = default(CloudStorageAccount);

            //detect fabric and use the fabric connection string; using directive to force cloud
            if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("_DF_STATE_DIRECTORY")))
            {
#if FORCE_LOCAL
                StorageAccount = CloudStorageAccount.FromConfigurationSetting("LocalStorageConnectionString");
#else
                StorageAccount = CloudStorageAccount.FromConfigurationSetting("CloudConnectionString");
#endif
            }
            else
            {
                StorageAccount = CloudStorageAccount.FromConfigurationSetting("LocalStorageConnectionString");
            }

            MoveFromFolderToContainer(ProjectResourcesDirRoot, BlobContainerName, StorageAccount);
        }

        static void MoveFromFolderToContainer(string FolderPath, string ContainerName, CloudStorageAccount StorageAccount)
        {
            //use the last folder name in path as the root and take it and any ancestor folders to the file name
            string[] FolderNamesArray = FolderPath.Split(new char[] {'\\'});
            string ResourceRootFolderName = FolderNamesArray[FolderNamesArray.Length -1];

            CloudBlobClient BlobClient = StorageAccount.CreateCloudBlobClient();
            CloudBlobContainer BlobContainer = BlobClient.GetContainerReference(StorageAccount.BlobEndpoint.ToString() + "/" + ContainerName);

            BlobRequestOptions options = new BlobRequestOptions();
            options.UseFlatBlobListing = true;

            //In case this is the first time that we are accessing/loading this container we'll call CreateIfNotExist() to ensure the container exists
            BlobContainer.CreateIfNotExist(options);

            BlobContainerPermissions permissions = new BlobContainerPermissions();
            permissions.PublicAccess = BlobContainerPublicAccessType.Container;
            BlobContainer.SetPermissions(permissions);

            //open file system
            System.IO.DirectoryInfo DirInfo = new DirectoryInfo(FolderPath);

            //call recursive function to load all contents and children of a directory into the storage container
            IterateFolders(DirInfo, BlobContainer, ResourceRootFolderName);
        }

        static void IterateFolders(DirectoryInfo CurrentDir, CloudBlobContainer TargetContainer, string RootFolderName)
        {

            DirectoryInfo[] ChildDirectories = CurrentDir.GetDirectories();

            //recurively iterate through all descendants of the source folder
            foreach (DirectoryInfo ChildDir in ChildDirectories)
            {
                IterateFolders(ChildDir, TargetContainer, RootFolderName);
            }

            //get the path name including only the rootfoldername and its decendants; it will be used as part of the filename
            string PreAppendPath = CurrentDir.FullName.Remove(0, CurrentDir.FullName.IndexOf(RootFolderName) + RootFolderName.Length);
            PreAppendPath = PreAppendPath.TrimStart("\\".ToCharArray()[0]);

            //get file list
            FileInfo[] FileList = CurrentDir.GetFiles();

            //iterate through files
            foreach (FileInfo file in FileList)
            {

                //filename + path and use as name in container; path + filename should be unique
                string NewFileName = (PreAppendPath + "\\" + file.Name).ToLower();
                
                //create a normal form for the filename: lcase + replace "\" with "/"
                //  Replacement of "\" is required to fix what seems to be a bug.  
                //  When the filename "folder\childfolder\filename.jpg" is saved it is ends up saved in dev storage as "folder/childfolder/filename.jpg".
                //  When we check to see if there is a matching filename using First<> it fails.  
                //  So, make the change to the filename ahead of time and it works fine for cloud deployment too.
                NewFileName = NewFileName.Replace(@"\", "/").ToLower();

                try
                {
                    //In previous versions we iterated through the file list and did not upload if the file existed in the blob container
                    //In this version we will always attempt to upload the file and set the AccessCondition to only work if the blob is older than our source file
                    BlobRequestOptions options = new BlobRequestOptions();
                    options.AccessCondition = AccessCondition.IfNotModifiedSince(file.LastWriteTimeUtc);

                    //write the file
                    //CloudBlob destBlob = TargetContainer.GetBlobReference(HttpUtility.UrlEncode (NewFileName));
                    CloudBlob destBlob = TargetContainer.GetBlobReference(NewFileName);

                    destBlob.UploadFile(file.FullName,options);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                }

            }

        }
    }
}
